package cn.ecnu.user.service.impl;

import cn.ecnu.common.Constant;
import cn.ecnu.common.RedisConstant;
import cn.ecnu.exception.RRXException;
import cn.ecnu.user.mapper.RoleMapper;
import cn.ecnu.user.mapper.UserMapper;
import cn.ecnu.user.pojo.Role;
import cn.ecnu.user.pojo.User;
import cn.ecnu.user.service.UserService;
import cn.ecnu.user.util.Encryptor;
import cn.ecnu.utils.PaginationUtil;
import cn.ecnu.user.util.TokenSolver;
import cn.ecnu.user.vo.*;
import cn.ecnu.vo.common.Pagination;
import cn.ecnu.vo.user.UserPermission;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

@Service
public class UserServiceImpl implements UserService {


    @Resource
    private UserMapper userMapper;

    @Resource
    private RoleMapper roleMapper;

    @Autowired
    private Encryptor encryptor;

    @Autowired
    private TokenSolver tokenSolver;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public UserInfoVo loginWithCaptcha(PhoneCaptchaVo vo) {
        // 首先在Redis中按照手机号查验证码
        String code = stringRedisTemplate.opsForValue().get(RedisConstant.SMS_PREFIX + vo.getPhone());
        // 比对code是否一致
        if (!StringUtils.equals(code, vo.getCaptcha()))
            throw new RRXException(Constant.CODE_ERROR.getMsg(), Constant.CODE_ERROR.getCode());

        // 如果一致, 在数据库中查找用户
        User user = userMapper.getUserByPhone(vo.getPhone());
        if (user == null) throw new RRXException(Constant.NO_USER.getMsg(), Constant.NO_USER.getCode()); // 首先判断用户是否存在
        Role role = roleMapper.getRoleById(user.getRole());
        String token = "";
        try {
            token = tokenSolver.sign(new UserPermission(user.getUserId(), role.getAuthority()));
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 生成用户信息返回
        UserInfoVo userInfoVo = new UserInfoVo();
        BeanUtils.copyProperties(user, userInfoVo);
        BeanUtils.copyProperties(role, userInfoVo);
        userInfoVo.setToken(token);

        // 删除redis中的验证码
        stringRedisTemplate.delete(RedisConstant.SMS_PREFIX + vo.getPhone());

        return userInfoVo;
    }

    @Override
    public UserInfoVo loginWithPassword(PhonePasswordVo vo) {
        User user = userMapper.getUserByPhone(vo.getPhone());
        if (user == null) throw new RRXException(Constant.NO_USER.getMsg(), Constant.NO_USER.getCode()); // 首先判断用户是否存在
        if (!StringUtils.equals(user.getPassword(), encryptor.encrypt(vo.getPassword(), user.getSalt())))  // 判断密码是否正确
            throw new RRXException(Constant.LOGIN_ERROR.getMsg(), Constant.LOGIN_ERROR.getCode());

        // 如果密码正确, 分发Token
        Role role = roleMapper.getRoleById(user.getRole());
        String token = "";
        try {
            token = tokenSolver.sign(new UserPermission(user.getUserId(), role.getAuthority()));
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 生成用户信息返回
        UserInfoVo userInfoVo = new UserInfoVo();
        BeanUtils.copyProperties(user, userInfoVo);
        BeanUtils.copyProperties(role, userInfoVo);
        userInfoVo.setToken(token);

        // 删除验证码
        stringRedisTemplate.delete(RedisConstant.SMS_PREFIX + vo.getPhone());
        return userInfoVo;
    }

    @Override
    public int registerWithPhone(RegisterWithPhoneVo vo) {

        // 首先在Redis中按照手机号查验证码
        String code = stringRedisTemplate.opsForValue().get(RedisConstant.SMS_PREFIX + vo.getPhone());

        // 比对code是否一致
        if (!StringUtils.equals(code, vo.getCaptcha()))
            throw new RRXException(Constant.CODE_ERROR.getMsg(), Constant.CODE_ERROR.getCode());

        // 对比用户手机号是否已经注册
        User user = userMapper.getUserByPhone(vo.getPhone());
        if (user != null) throw new RRXException(Constant.USER_EXISTS.getMsg(), Constant.USER_EXISTS.getCode());

        // 注册这个用户
        String salt = encryptor.salt(); // 获得盐
        User userToStore = new User();
        BeanUtils.copyProperties(vo, userToStore);
        userToStore.setEmail(null);
        userToStore.setFlag(1); // 用户可用
        userToStore.setSalt(salt);
        userToStore.setPassword(encryptor.encrypt(vo.getPassword(), salt)); // 加密密码
        userToStore.setRole(1);
        userToStore.setAvatar("https://pic1.zhimg.com/v2-0f112f8959933737e7ef7510f7e66a1a_is.jpg");

        // 删除验证码
        stringRedisTemplate.delete(RedisConstant.SMS_PREFIX + vo.getPhone());
        return userMapper.addUser(userToStore);
    }

    @Override
    public UserInfoVo loginWithAlipay(String alipayId) {

        // 首先在数据库中按照支付宝ID查找用户
        User user = userMapper.getUserByAlipayId(alipayId);
        if (user == null) {
            UserInfoVo noUser = new UserInfoVo();
            noUser.setAlipayId(alipayId);
            return noUser;
        }
        Role role = roleMapper.getRoleById(user.getRole());
        String token = "";
        try {
            token = tokenSolver.sign(new UserPermission(user.getUserId(), role.getAuthority()));
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 生成用户信息返回
        UserInfoVo userInfoVo = new UserInfoVo();
        BeanUtils.copyProperties(user, userInfoVo);
        BeanUtils.copyProperties(role, userInfoVo);
        userInfoVo.setToken(token);
        return userInfoVo;
    }

    // 设置PageSize = 2
    @Override
    public AdminAllUser getAllUsersPage(Integer pageNum) {
        int pageSize = 10; // TODO: 后面需要修改
        Integer totalSize = userMapper.getTotal(); // 获取总共的数目
        Pagination pagination = PaginationUtil.paging(pageNum, totalSize, pageSize, "/user/list");
        pageNum = pagination.getCurrentPage();
        // TODO: 多线程
        AdminAllUser vo = new AdminAllUser();
        List<AdminUserVo> users = userMapper.getAdminUserVo((pageNum - 1) * pageSize, pageSize); // 首先获取所有的用户
        vo.setUsers(users); vo.setPagination(pagination);
        return vo;
    }

    @Override
    public AdminAllUser getAllUsers() {
        AdminAllUser vo = new AdminAllUser();
        List<AdminUserVo> users = userMapper.getAdminUserVoAll();
        vo.setUsers(users);
        return vo;
    }

    @Override
    public AdminUserVo getUserAdminVoByUid(Integer uid) {
        return userMapper.getUserVoById(uid);
    }

    @Override
    public int deleteUserById(Integer uid) {
        return userMapper.deleteUserById(uid);
    }


    @Override
    public AdminUserVo changeUserRole(ChangeRoleVo vo) {
        if (vo.getRoleId() == null || vo.getUserId() == null) throw new RRXException(Constant.ARGUMENT_INVALID.getMsg(), Constant.ARGUMENT_INVALID.getCode());
        userMapper.changeUserRole(vo.getUserId(), vo.getRoleId());
        return userMapper.getUserVoById(vo.getUserId());
    }


    @Override
    public int updateUserById(UserInfoVo vo) {
        return userMapper.updateUserVoById(vo);
    }
}
